﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DcsGauges.Input.Events;
using DcsGauges.Gui.Rendering.Interfaces;
using Microsoft.Xna.Framework;

namespace DcsGauges.Input.Processors
{
    class SwipeProcessor
    {
        #region Inner Types

        public enum SwipeAxis
        {
            Horizontal,
            Vertical,
        }

        public class SwipeEventArgs : EventArgs
        {
            public enum SwipeDirections
            {
                Positive, 
                Negative,
            }

            public SwipeDirections              Direction               { get; private set; }
            public int                          Delta                   { get; private set; }
            public SwipeAxis                    Axis                    { get; private set; }

            public SwipeEventArgs(int delta, SwipeAxis axis)
            {
                this.Delta              = delta;
                this.Direction          = delta > 0 ? SwipeDirections.Positive : SwipeDirections.Negative;
                this.Axis               = axis;
            }
        }

        public delegate int CalcDeltaDelegate(Point start, MouseEvent evt, GameTime gt);

        #endregion


        #region Constants / Readonly

        private const uint                      MIN_DELTA                   = 30;

        #endregion


        #region Fields / Properties

        private CalcDeltaDelegate               CalcDelta                   = null;
        private uint                            minDeltaTillSwipe           = MIN_DELTA;
        private IGuiRenderable                  guiElement                  = null;
        private Point?                          swipeStart                  = null;
        private SwipeAxis                       axis                        = SwipeAxis.Horizontal;

        private bool IsWaitingForSwipe
        {
            get { return this.swipeStart.HasValue; }
        }

        #endregion


        #region Events

        public event EventHandler<SwipeEventArgs>               SwipeEvent                  = delegate { };

        #endregion

        public SwipeProcessor(IGuiRenderable guiElement, CalcDeltaDelegate calcDelta, SwipeAxis axis)
        {
            this.guiElement                 = guiElement;
            this.CalcDelta                  = calcDelta;
            this.axis                       = axis;
        }

        public void InjectMouseEvent(MouseEvent evt, GameTime gt)
        {
            int delta = 0;
            if(this.IsWaitingForSwipe)
            {
                delta = this.CalcDelta(this.swipeStart.Value, evt, gt);
            }

            if (!this.IsWaitingForSwipe && evt.Button == MouseEvent.MouseButtons.Left && evt.EventType == MouseEvent.EventTypes.MouseDown && this.guiElement.ViewportRect.Contains(evt.ScreenCoordinates))
            {
                this.EnterWaitForSwipeState(evt);
            }
            else if (this.IsWaitingForSwipe && evt.Button == MouseEvent.MouseButtons.Left && evt.EventType == MouseEvent.EventTypes.MouseUp && Math.Abs(delta) >= minDeltaTillSwipe)
            {
                this.FireSwipeEvent(evt.ScreenCoordinates.Y - this.swipeStart.Value.Y);
                this.LeaveWaitForSwipeState();
            }
            else if (this.IsWaitingForSwipe && evt.Button == MouseEvent.MouseButtons.Left && evt.EventType == MouseEvent.EventTypes.MouseUp && Math.Abs(delta) < minDeltaTillSwipe)
            {
                this.LeaveWaitForSwipeState();
            }
            else if (this.IsWaitingForSwipe && evt.Button != MouseEvent.MouseButtons.Left)
            {
                this.LeaveWaitForSwipeState();
            }
        }


        #region Helpers 

        private void EnterWaitForSwipeState(MouseEvent evt)
        {
            this.swipeStart             = evt.ScreenCoordinates;
        }

        private void LeaveWaitForSwipeState()
        {
            this.swipeStart             = null;
        }

        private void FireSwipeEvent(int delta)
        {
            if(this.SwipeEvent != null)
            {
                this.SwipeEvent(this, new SwipeEventArgs(delta, this.axis));
            }
        }

        #endregion
    }
}
